#include <Accepter.h>

static void AccepterListenCallback(struct evconnlistener* listener, socket_t sockfd, struct sockaddr* addr, int socklen, void* arg)
{
	Accepter* accepter = (Accepter*)(arg);
	accepter->onAcceptConnection(sockfd);
}

Accepter::Accepter(event_base* base, socket_t listenFd, int backlog) :
	listenfd_(listenFd),
	base_(base),
	backlog_(backlog),
	listener_(evconnlistener_new(base, AccepterListenCallback, this, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, backlog, listenFd))
{
	assert(listener_);
	initAddress();
}

Accepter::Accepter(event_base* base, const InetAddress& listenAddr, int backlog)
	:base_(base),
	backlog_(backlog),
	listenAddr_(listenAddr)
{
	sockaddr_in sockAddr = listenAddr_.getSockAddr();
	SockLen socklen = sizeof(sockAddr);
	listener_ = evconnlistener_new_bind(base, AccepterListenCallback, this , LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, backlog, (sockaddr*)(&sockAddr), socklen);
	listenfd_ = evconnlistener_get_fd(listener_);
	initAddress();
}

Accepter::~Accepter()
{
	if (listener_ != nullptr) {
		evconnlistener_free(listener_);
	}
}

bool Accepter::bind(const InetAddress& addr)
{
	if (listener_ != nullptr) {
		evconnlistener_free(listener_);
		listener_ = nullptr;
	}
	listenAddr_ = addr;
	sockaddr_in sockAddr = listenAddr_.getSockAddr();
	SockLen socklen = sizeof(sockAddr);
	listener_ = evconnlistener_new_bind(base_, AccepterListenCallback, this, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, backlog_, (sockaddr*)(&sockAddr), socklen);
	initAddress();
	return listener_ != nullptr;
}

bool Accepter::startListen()
{
	return evconnlistener_enable(listener_) == 0;
}

socket_t Accepter::getfd()
{
	if (!listener_) {
		return -1;
	}
	return evconnlistener_get_fd(listener_);
}

std::string Accepter::getIPv4Address()
{
	return listenAddr_.ip();
}

uint16_t Accepter::getPort()
{
	return listenAddr_.port();
}

bool Accepter::stopListen()
{
	return evconnlistener_disable(listener_) == 0;
}

void Accepter::initAddress()
{
	sockaddr_in addr;
	SockLen len = sizeof(addr);
	if (getsockname(listenfd_, (sockaddr*)&addr, &len) != 0)
	{
		perror("getsockname");
		assert(false);
		return;
	}
	listenAddr_ = *(sockaddr*)(&addr);
}
